package com.cooper.android.comm;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Shader.TileMode;

public class BitmapUtils {

	public static int dip2px(Resources res, float dpValue) {
		final float scale = res.getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

	public static int px2dip(Resources res, float pxValue) {
		final float scale = res.getDisplayMetrics().density;
		return (int) (pxValue / scale + 0.5f);
	}

	public static Bitmap decodeFile(File file, float width, float height,
			boolean keepScale) throws FileNotFoundException {

		if (file.exists()) {
			BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();
			bitmapFactoryOptions.inJustDecodeBounds = true;
			Bitmap result = BitmapFactory.decodeFile(file.getPath(),
					bitmapFactoryOptions);

			int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight
					/ height);
			int xRatio = (int) Math.ceil(bitmapFactoryOptions.outWidth / width);

			if (yRatio > 1 || xRatio > 1) {
				if (yRatio > xRatio) {
					bitmapFactoryOptions.inSampleSize = yRatio;
				} else {
					bitmapFactoryOptions.inSampleSize = xRatio;
				}
			}

			bitmapFactoryOptions.inJustDecodeBounds = false;
			result = BitmapFactory.decodeFile(file.getPath(),
					bitmapFactoryOptions);
			if (!keepScale) {
				Bitmap temp = result;
				result = Bitmap.createScaledBitmap(temp, (int) width,
						(int) height, true);
				if (temp != null && !temp.isRecycled()){
					temp.recycle();
				}
			}
			return result;
		} else {
			throw new FileNotFoundException(file.getPath());
		}
	}

	public static Bitmap reflectedFanart(Bitmap bitmap) {
		// The gap we want between the reflection and the original image
		// final int reflectionGap = 4;

		Bitmap originalImage = bitmap;
		int width = originalImage.getWidth();
		int height = originalImage.getHeight();

		// This will not scale but will flip on the Y axis
		Matrix matrix = new Matrix();
		matrix.preScale(1, -1);

		// Create a Bitmap with the flip matrix applied to it.
		// We only want the bottom half of the image
		// Log.d("IMAGE", "y:" + (height / 2 * 3) + "newH:" + height / 3 +
		// "ooH:" + height);
		Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
				(height * 2 / 3), width, height / 3, matrix, false);

		// Create a new bitmap with same width but taller to fit
		// reflection
		Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
				(height + height / 3), Config.ARGB_8888);

		// Create a new Canvas with the bitmap that's big enough for
		// the image plus gap plus reflection
		Canvas canvas = new Canvas(bitmapWithReflection);
		// Draw in the original image
		canvas.drawBitmap(originalImage, 0, 0, null);
		// Draw in the gap
		// Paint deafaultPaint = new Paint();
		// canvas.drawRect(0, height, width, height + reflectionGap,
		// deafaultPaint);
		// Draw in the reflection
		canvas.drawBitmap(reflectionImage, 0, height, null);

		// Create a shader that is a linear gradient that covers the
		// reflection
		Paint paint = new Paint();
		LinearGradient shader = new LinearGradient(0,
				originalImage.getHeight(), 0, bitmapWithReflection.getHeight(),
				0x70ffffff, 0x00ffffff, TileMode.CLAMP);
		// Set the paint to use this shader (linear gradient)
		paint.setShader(shader);
		// Set the Transfer mode to be porter duff and destination in
		paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
		// Draw a rectangle using the paint with our linear gradient
		canvas.drawRect(0, height, width, bitmapWithReflection.getHeight(),
				paint);

		if (originalImage != null && !originalImage.isRecycled()) {
			originalImage.recycle();
		}
		if (reflectionImage != null && !reflectionImage.isRecycled()) {
			reflectionImage.recycle();
		}
		return bitmapWithReflection;
	}

	public static Bitmap roundRect(Bitmap bitmap, float radius) {
		return roundRect(bitmap, radius, true);
	}

	public static Bitmap roundRect(Bitmap bitmap, float radius,
			boolean recycleSource) {
		Bitmap result = Bitmap.createBitmap(bitmap.getWidth(),
				bitmap.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(result);
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, result.getWidth(), result.getHeight());
		final RectF rectF = new RectF(rect);
		canvas.drawRoundRect(rectF, radius, radius, paint);
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(bitmap, rect, rect, paint);
		if (recycleSource && !bitmap.isRecycled()) {
			bitmap.recycle();
		}
		return result;
	}

	public static Bitmap drawOverlay(Bitmap source, Bitmap overlay,
			float padding, boolean recycleSource) {
		Bitmap scaledOverlay = Bitmap.createScaledBitmap(overlay,
				(int) (source.getWidth() + padding * 2),
				(int) (source.getHeight() + padding * 2), true);
		Bitmap result = Bitmap.createBitmap(scaledOverlay.getWidth(),
				scaledOverlay.getHeight(), Config.ARGB_8888);

		Canvas canvas = new Canvas(result);
		final Paint paint = new Paint();
		canvas.drawBitmap(source, padding, padding, paint);
		// paint.setXfermode(new PorterDuffXfermode(Mode.values()[i++]));
		canvas.drawBitmap(scaledOverlay, 0f, 0f, paint);
		if (!scaledOverlay.isRecycled()) {
			scaledOverlay.recycle();
		}
		if (recycleSource && !source.isRecycled()) {
			source.recycle();
		}
		return result;
	}

	public static class FlushedInputStream extends FilterInputStream {
		public FlushedInputStream(InputStream inputStream) {
			super(inputStream);
		}

		@Override
		public long skip(long n) throws IOException {
			long totalBytesSkipped = 0L;
			while (totalBytesSkipped < n) {
				long bytesSkipped = in.skip(n - totalBytesSkipped);
				if (bytesSkipped == 0L) {
					int b = read();
					if (b < 0) {
						break; // we reached EOF
					} else {
						bytesSkipped = 1; // we read one byte
					}
				}
				totalBytesSkipped += bytesSkipped;
			}
			return totalBytesSkipped;
		}
	}

}
